package com.yuandian.utils;

import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import com.yuandian.constant.Constants;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 〈p〉
 * 字符串工具类
 * 〈p〉
 *
 * @author VaeTang
 * @date 2019/05/18
 * @since 1.0.0
 */
public class StringUtils extends StrUtil {

    /**
     * 生成32位随机字符串
     *
     * @return
     */
    public static String getUUID() {
        UUID uuid = UUID.randomUUID();
        String uuidStr = uuid.toString().toUpperCase();
        if (isNullOrEmpty(uuidStr)) {
            return "";
        }
        return uuidStr.replace("-", "");
    }

    /**
     * 判断一个对象是否为空
     *
     * @param obj 对象或字符串
     * @return true：为空 false：非空
     */
    public static boolean isNullOrEmpty(final Object obj) {
        return isNull(obj) || Constants.EMPTY_STRING.equals(obj.toString().trim());
    }


    /**
     * * 判断一个Collection是否为空， 包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Collection<?> coll) {
        return isNull(coll) || coll.isEmpty();
    }

    /**
     * * 判断一个Collection是否非空，包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * * 判断一个对象数组是否为空
     *
     * @param objects 要判断的对象数组
     *                * @return true：为空 false：非空
     */
    public static boolean isEmpty(Object[] objects) {
        return isNull(objects) || (objects.length == 0);
    }

    /**
     * * 判断一个对象数组是否非空
     *
     * @param objects 要判断的对象数组
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Object[] objects) {
        return !isEmpty(objects);
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return isNull(map) || map.isEmpty();
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * * 判断一个字符串是否为空串
     *
     * @param str String
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(String str) {
        return isNull(str) || Constants.EMPTY_STRING.equals(str.trim());
    }

    /**
     * * 判断多个字符串是否为空串
     *
     * @param strs String[]
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(String ... strs) {
        for (String str : strs) {
            if (isEmpty(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * * 判断一个字符串是否为非空串
     *
     * @param str String
     * @return true：非空串 false：空串
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * * 判断多个字符串是否为非空串
     *
     * @param strs String[]
     * @return true：非空串 false：空串
     */
    public static boolean isNotEmpty(String ... strs) {
        for (String str : strs) {
            if (isEmpty(str)) {
                return false;
            }
        }
        return true;
    }

    /**
     * * 判断一个对象是否为空
     *
     * @param object Object
     * @return true：为空 false：非空
     */
    public static boolean isNull(Object object) {
        return object == null;
    }

    /**
     * * 判断一个对象是否非空
     *
     * @param object Object
     * @return true：非空 false：空
     */
    public static boolean isNotNull(Object object) {
        return !isNull(object);
    }

    /**
     * * 判断一个对象是否是数组类型（Java基本型别的数组）
     *
     * @param object 对象
     * @return true：是数组 false：不是数组
     */
    public static boolean isArray(Object object) {
        return isNotNull(object) && object.getClass().isArray();
    }

    /**
     * 去空格
     */
    public static String trim(String str) {
        return (str == null ? "" : str.trim());
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @return 结果
     */
    public static String substring(final String str, int start) {
        if (str == null) {
            return Constants.EMPTY_STRING;
        }

        if (start < 0) {
            start = str.length() + start;
        }

        if (start < 0) {
            start = 0;
        }
        if (start > str.length()) {
            return Constants.EMPTY_STRING;
        }

        return str.substring(start);
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @param end   结束
     * @return 结果
     */
    public static String substring(final String str, int start, int end) {
        if (str == null) {
            return Constants.EMPTY_STRING;
        }

        if (end < 0) {
            end = str.length() + end;
        }
        if (start < 0) {
            start = str.length() + start;
        }

        if (end > str.length()) {
            end = str.length();
        }

        if (start > end) {
            return Constants.EMPTY_STRING;
        }

        if (start < 0) {
            start = 0;
        }
        if (end < 0) {
            end = 0;
        }

        return str.substring(start, end);
    }

    /**
     * 格式化文本, {} 表示占位符<br>
     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
     * 如果想输出 {} 使用 \\转义 { 即可，如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
     * 例：<br>
     * 通常使用：format("this is {} for {}", "a", "b") -> this is a for b<br>
     * 转义{}： format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
     * 转义\： format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
     *
     * @param template 文本模板，被替换的部分用 {} 表示
     * @param params   参数值
     * @return 格式化后的文本
     */
    public static String format(String template, Object... params) {
        if (isEmpty(params) || isEmpty(template)) {
            return template;
        }
        return StrFormatter.format(template, params);
    }

    /**
     * 字符串转set
     *
     * @param str 字符串
     * @param sep 分隔符
     * @return set集合
     */
    public static final Set<String> str2Set(String str, String sep) {
        return new HashSet<String>(str2List(str, sep, true, false));
    }

    /**
     * 字符串转list
     *
     * @param str         字符串
     * @param sep         分隔符
     * @param filterBlank 过滤纯空白
     * @param trim        去掉首尾空白
     * @return list集合
     */
    public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
        List<String> list = new ArrayList<String>();
        if (StringUtils.isEmpty(str)) {
            return list;
        }

        // 过滤空白字符串
        if (filterBlank && StringUtils.isBlank(str)) {
            return list;
        }
        String[] split = str.split(sep);
        for (String string : split) {
            if (filterBlank && StringUtils.isBlank(string)) {
                continue;
            }
            if (trim) {
                string = string.trim();
            }
            list.add(string);
        }

        return list;
    }

    /**
     * 下划线转驼峰命名
     */
    public static String toUnderScoreCase(String str) {
        if (str == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        // 前置字符是否大写
        boolean preCharIsUpperCase = true;
        // 当前字符是否大写
        boolean curreCharIsUpperCase = true;
        // 下一字符是否大写
        boolean nexteCharIsUpperCase = true;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i > 0) {
                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
            } else {
                preCharIsUpperCase = false;
            }

            curreCharIsUpperCase = Character.isUpperCase(c);

            if (i < (str.length() - 1)) {
                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
                sb.append(Constants.SEPARATOR);
            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
                sb.append(Constants.SEPARATOR);
            }
            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(String str, String... strs) {
        if (str != null && strs != null) {
            for (String s : strs) {
                if (str.equalsIgnoreCase(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。 例如：HELLO_WORLD->HelloWorld
     *
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String convertToCamelCase(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母大写
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        // 用下划线将原始字符串分割
        String[] camels = name.split("_");
        for (String camel : camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            // 首字母大写
            result.append(camel.substring(0, 1).toUpperCase());
            result.append(camel.substring(1).toLowerCase());
        }
        return result.toString();
    }

    /**
     * 驼峰式命名法 例如：user_name->userName
     */
    public static String toCamelCase(String s) {
        if (s == null) {
            return null;
        }
        s = s.toLowerCase();
        StringBuilder sb = new StringBuilder(s.length());
        boolean upperCase = false;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            if (c == Constants.SEPARATOR) {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
    /**
     * @Description 将驼峰转为下划线
     * @param str
     * @return java.lang.String
     */
    public static String toUnderlineName(String str) {
        Pattern compile = Pattern.compile("[A-Z]");
        Matcher matcher = compile.matcher(str);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()) {
            matcher.appendReplacement(sb,  "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }


    /**
	 * 去掉字符串左右空格，并解码为UTF-8格式，如果字符串未空，则返回"";
	 */
	public static String decodeUTF8(String value){

		try{
			if(value!=null) value = java.net.URLEncoder.encode(value, "utf-8");

		}catch(java.io.UnsupportedEncodingException e){

		}
		return value==null? "":value.trim();
	}

	public static String encodeUTF8(String value){

		try{
			if(value!=null) value = java.net.URLEncoder.encode(value, "utf-8");

		}catch(java.io.UnsupportedEncodingException e){

		}
		return value==null? "":value.trim();
	}

	public static String convertToUTF8(String value){
		try{

			if(value!=null) value =  new String(value.getBytes("ISO-8859-1"), "UTF-8");

		}catch(java.io.UnsupportedEncodingException e){

		}
		return value==null? "":value.trim();
	}

	public static boolean isNotNull(String str){
		return str!=null && str.trim().length()>0;
	}

	/**
	 * @param def 默认值
	 * @return Integer
	 */
	public static String getStringValues (String value, Integer def) {
		return (null == value || value.trim().length() == 0) ? String.valueOf(def) : value;
	}

	public static String getStringValues (String value, String def) {
		return (null == value || value.trim().length() == 0) ? def : value;
	}

	public static Integer getIntegerValues (String value, Integer def) {
		return (null == value || value.trim().length() == 0) ? def : Integer.parseInt(value);
	}

    /**
     * 生成md5
     * 1、用于服务资源编码的生成
     * 2、用于专属指标code的生成
     * @param plainText
     * @return
     */
    public static String generate16Md5(String plainText) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();

            int i;

            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            return buf.toString().substring(8, 24);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "0000000000000000";
    }

	//============前端=============
	/**
	 * 判断对象是否为null或为""
	 * @param obj
	 * @return
	 */
	public static boolean isNotBlank(Object obj) {
		if (obj == null || "".equals(obj.toString().trim())) {
			return false;
		}
		return true;
	}

	/**
	 * 转换成int
	 * @param obj
	 * @return
	 */
	public static int convert2Int(Object obj) {
		int result = 0;
		if(obj==null)return result;
		if (obj instanceof Integer)
			result = ((Integer) obj).intValue();
		else {

			if (obj.toString().trim().length() > 0) {
				try {
					result = Integer.parseInt(obj.toString());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return result;

	}
	//===========================

	/**
	 * 字符串首字母转大写
	 * @param field
	 * @return
	 */
	public static String firstCharToUpperCase(String field) {
		char[] chars = field.toCharArray();
		if (chars[0] >= 'a' && chars[0] <= 'z'){
			chars[0] -= 32;
			return String.valueOf(chars);
		}
		return field;
	}

	/**
	 * 打印详细的异常信息到日志文件里面。
	 * @param e
	 * @return
	 */
	public static String exceptionStackToString(Throwable e) {
	    if(e==null)return "";
	    ByteArrayOutputStream out = new ByteArrayOutputStream();
	    PrintStream stream = new PrintStream(out);
	    e.printStackTrace(stream);
	    return out.toString();
	}

	/**
     * 判断字符串是否是数字
     *
     */
    public static boolean isNumeric(String str) {
        if (str == null) {
            return false;
        }
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    /**
     * 驼峰命名转下划线命名
     *
     * @param s
     * @return
     */
    public static String humpToLine(String s) {
        if (StringUtils.isEmpty(s)){
            return null;
        }
        Pattern humpPattern = Pattern.compile("[A-Z]");
        Matcher matcher = humpPattern.matcher(s);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, Constants.SEPARATOR + matcher.group(0));
        }
        matcher.appendTail(sb);
        return sb.toString().toLowerCase();
    }

    /**
     * 返回字符在字符串中第n次出现的下标位置
     * @param sourceStr
     * @param findStr
     * @param num
     * @return 返回-1，表示该字符不存在字符串或者字符串不够n个该字符。返回的下标从0开始计算
     */
    public static int subscriptSubStr(String sourceStr, String findStr, int num) {
        int count = 0;
        int index = -1;
        Matcher matcher = Pattern.compile(findStr).matcher(sourceStr);
        while (matcher.find()) {
            count ++;
            if (num == count) {
                break;
            }
        }
        if (count > 0 && num == count) {
            index = matcher.start();
        }
        return index;
    }

    /**
     * 校验文件名合法性:
	 * 避免使用加号、减号或者"."作为普通文件的第一个字符
	 * 文件名避免使用下列特殊字符,包括制表符和退格符
     * @param fileName
     * @return 合法返回true，不合法返回false
     */
    public static boolean checkFileName (String fileName) {
		String regex = "^[^+-./\t\b@#$%*()\\[\\]][^/\t\b@#$%*()\\[\\]]{1,254}$";
		return fileName.matches(regex);
    }

	public static void main(String[] args) {
		System.out.println(checkFileName("1../sdf.doc"));

	}

}
